How to reduce a Seq[Either[A,B]] to a Either[Seq[A],Seq[B]]?

Edit: I missed that the title of your question asked for EitherSeqA,SeqB but I did read "I'd like to obtain the first error message or a concatenation of all error messages", and this would give you the former.

Edit: I missed that the title of your question asked for EitherSeqA,SeqB, but I did read "I'd like to obtain the first error message or a concatenation of all error messages", and this would give you the former: def reduceA, B(s: SeqEitherA, B): EitherA, SeqB = s. FoldLeft(Right(Nil): EitherA, ListB) { (acc, e) => for (xs reduce(List(Right(1), Right(2), Right(3))) res2: EitherNothing,SeqInt = Right(List(1, 2, 3)) scala> reduce(List(Right(1), Left("error"), Right(3))) res3: Eitherjava.lang. String,SeqInt = Left(error) Here's an example using Scalaz: type EitherStringA = EitherString, A val xs: SeqEitherString, Int = List(Right(1), Right(2), Right(3)) scala> xs.

SequenceEitherString, Int res0: EitherStringSeqInt = Right(List(1, 2, 3)) The type alias is so that you can pass a unary type constructor (is that the correct term? ) as the first type parameter to sequence. I struggled for a bit trying make a succinct, A, B parameterised version of this, but my best effort so far is: trait EitherSequenceA, B { type EitherAB = EitherA, B def sequence(xs: SeqEitherA, B) = xs.

SequenceEitherA, B } def sequenceA, B(xs: SeqEitherA, B) = (new EitherSequenceA, B {}). Sequence(xs).

That's shorter than my solution, which uses matching. I think you could use a for-comprehension to make the fold funciton more readable. – ziggystar Aug 29 '11 at 14:32 Yes, you could replace the body of the function in the foldLeft with: for (xs Right; x.

It should work: def unfoldResA(x: SeqEitherString, A) = x partition {_. IsLeft} match { case (Seq(), r) => Right(r map {_.right. Get}) case (l, _) => Left(l map {_.left.

Get} mkString "\n") } You split your result in left and right, if left is empty, build a Right, otherwise, build a left.

Given a starting sequence xs, here's my take: xs collectFirst { case x@Left(_) => x } getOrElse Right(xs collect {case Right(x) => x}) This being in answer to the body of the question, obtaining only the first error as an EitherString,SeqA. It's obviously not a valid answer to the question in the title To return all errors: val lefts = xs collect {case Left(x) => x } def rights = xs collect {case Right(x) => x} if(lefts. IsEmpty) Right(rights) else Left(lefts) Note that rights is defined as a method, so it'll only be evaluated on demand, if necessary.

I can only assume that the downvote, without explanation, is by someone who's tactically voting and trying to make their own answer appear preferable... – Kevin Wright Aug 29 '11 at 20:20 +1 Nice solutions. IMHO downvoters should be required to state a reason. – Landei Aug 30 '11 at 8:28 Does not require a downvote but second solution may leads to 2 traversal of the list, while you canseparate left from right in a single traversal – Nicolas Aug 30 '11 at 9:06 @Nicolas: True, but it's a fair trade, clarity vs premature optimisation.It's rare to see problems of this nature reach a large enough size that the performance hit would be noticable.

– Kevin Wright Aug 30 '11 at 12:44.

Building on Kevin's solution, and stealing a bit from Haskell's Either type, you can create a method partitionEithers like so: def partitionEithersA, B(es: SeqEitherA, B): (SeqA, SeqB) = es. FoldRight (Seq. EmptyA, Seq.

EmptyB) { case (e, (as, bs)) => e. Fold (a => (a +: as, bs), be => (as, be +: bs)) } And use that to build your solution def unrollA, B(es: SeqEitherA, B): EitherSeqA, SeqB = { val (as, bs) = partitionEithers(es) if (!as. IsEmpty) Left(as) else Right(bs) }.

I'm not used to use Either - here is my approach; maybe there are more elegant solutions: def condense A (sesa: Seq Either String, A): Either String, Seq A = { val l = sesa. Find (e => e. IsLeft) if (l == None) Right (sesa.

Map (e => e.right. Get)) else Left (l.get.left. Get) } condense (List (Right (3), Right (4), Left ("missing"), Right (2))) // EitherString,SeqInt = Left(missing) condense (List (Right (3), Right (4), Right (1), Right (2))) // EitherString,SeqInt = Right(List(3, 4, 1, 2)) Left (l.get.left.

Get) looks a bit funny, but l itself is a Either A, B, not an Either A, SeqB, and needs rewrapping.

You're not relying on the typing - beware the typists! – ziggystar Aug 29 '11 at 15:59 You mean the sesa. Map, returning a list?

A toSeq should fix that. – user unknown Aug 29 '11 at 16:14 What I meant was that you're asserting a condition in line 2 which you implicitly use in line three, where you write 'e.right. Get'.E.g.

The accepted answer doesn't leave the "safety of the typing". – ziggystar Aug 29 '11 at 19:41 I'm sorry, I can't follow. How do I leave the safety of typing?

Either it is a left, then it is found by find, or it is a Right, which I can get with e.right. Get; don't I? Can you provide an example, which shows the problem?

– user unknown Aug 29 '11 at 23:16 1 I'm not really sure if what I'm telling makes sense at all: In the second line you assert that there is no error if l is None. Then you use this knowledge (which is in your head) to write the . Get of which you know it will never fail, although .

Get can throw. If you look at Ben James' answer, he never calls a method that might possibly fail. – ziggystar Aug 29 '117 at 7:25.

Because there's no canonical treatment of a mixed sequence. If so, is the choice of implementation defined by the fact that the lefts are usually error messages? – ziggystar Sep 15 '11 at 10:07 Yes, that is the canonical example and is also the one described by the OP.

An alternative implementation joins errors values with a semigroup. – Tony Morris Sep 16 '11 at 5:03 I couldn't get this to work (using 6.0.4-SNAPSHOT) without explicitly supplying the type parameters to sequence. Otherwise, I get: Cannot prove that EitherString,Int Sorry I left that off.

I'll give you a more concrete example at the REPL if you can't get going. – Tony Morris Oct 16 '11 at 23:01 By the way, I have given a 1 hour talk on this very function. I have slides but no video.

I'm not sure how helpful slides will be, but here they are dl.dropbox.com/u/7810909/docs/applicative-errors-scala/… – Tony Morris Oct 16 '11 at 23:02.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions